package by.kniazhych.core.server.local {
	
	/**
	 * ...
	 * @author Boutylin Mikhail
	 */
	
	import by.kniazhych.core.server.common.ClientCommands;
	import by.kniazhych.core.server.common.IServerProxy;
	import by.kniazhych.core.server.common.ServerActionCommand;
	import by.kniazhych.core.server.common.ServerCommands;
	import by.vaukalak.core.commands.Command;
	import by.vaukalak.core.commands.CommandDispatcher;
	import by.vaukalak.core.commands.ICommandDispatcher;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	public class LocalServerProxy extends CommandDispatcher implements IServerProxy{
		
		//--------------------------------------------------------------------------
		//
		//  PRIVATE METHODS
		//
		//--------------------------------------------------------------------------
		
		private var _server:LocalServer;
		private var _client:ICommandDispatcher;
		private const _commandStack:CommandStack = new CommandStack();
		
		//--------------------------------------------------------------------------
		//
		//  CONSTRUCTOR
		//
		//--------------------------------------------------------------------------
		
		public function LocalServerProxy() {
			_server = new LocalServer(this);
			_server.addCommandListener(ServerCommands.BUILD_GAME, _stackCommand);
			_server.addCommandListener(ServerCommands.PROCESS_MOTION, _stackCommand);
			_server.addCommandListener(ServerCommands.NOTIFY_USER, _stackCommand);
			_server.addCommandListener(ServerCommands.CHANGE_PEACE, _stackCommand);
			_server.addCommandListener(ServerCommands.GIVE_TURN, _stackCommand);
			_server.addCommandListener(ServerCommands.DISPLAY_PEACE_CHOISE, _stackCommand);
		}
		
		//--------------------------------------------------------------------------
		//
		//  PUBLIC METHODS
		//
		//--------------------------------------------------------------------------
		
		public function shiftActionCommand():ServerActionCommand {
			return _commandStack.shift();
		}
		
		public function hasCommandsToExecute():Boolean {
			return _commandStack.hasCommandToExecute;
		}
		
		/* INTERFACE by.kniazhych.core.server.common.IServerProxy */
		
		public function observeClient(controller:ICommandDispatcher):void{
			_client = controller;
			_client.addCommandListener(ClientCommands.CONNECT, _executeClientCommand);
			_client.addCommandListener(ClientCommands.MOTION_REQUEST, _executeClientCommand);
			_client.addCommandListener(ClientCommands.SELECT_PEACE, _executeClientCommand);
		}
		
		//--------------------------------------------------------------------------
		//
		//  DELEGATING COMMANDS
		//
		//--------------------------------------------------------------------------
		
		private function _stackCommand(command:ServerActionCommand):void {
			var canDispatch:Boolean = !_commandStack.hasCommandToExecute;
			_commandStack.push(command);
			if (canDispatch && _commandStack.hasCommandToExecute) {
				dispatchCommand(new Command(ServerCommands.EXECUTE_ACTIONS));
			}
		}
		
		private function _executeClientCommand(command:Command):void {
			command.call(_server);
		}
		
		private function _executeServerCommand(command:Command):void {
			command.call(_client);
		}
	}

}

//--------------------------------------------------------------------------
//
//  INNER DEFINITIONS
//
//--------------------------------------------------------------------------

import by.kniazhych.core.server.common.ServerActionCommand;
import by.kniazhych.core.server.common.ServerActionFlag;
import flash.errors.IllegalOperationError;

class CommandStack {
	
	private const _commands:Vector.<ServerActionCommand> = new Vector.<ServerActionCommand>();
	
	public function CommandStack() {
	}
	
	public function push(command:ServerActionCommand):void {
		_commands.push(command);
		for (var i:int = 0; i < _commands.length - 1; i++) {
			if (_commands[i].commandIndex > command.commandIndex) {
				for (var j:int = _commands.length - 1; j > i; j--) {
					_commands[j] = _commands[j - 1];
				}
				_commands[i] = command;
				break;
			}
		}
	}
	
	public function get hasCommandToExecute():Boolean {
		
		if (!(_commands.length && _commands[0].isFirstCommand)) return false;
		var lastCommandIndex:int = _commands[0].commandIndex - 1;
		for (var i:int = 0; i < _commands.length; i++) {
			
			if (_commands[i].commandIndex - lastCommandIndex != 1)
				return false;
			else
				lastCommandIndex = _commands[i].commandIndex;
				
			if (_commands[i].isLastCommand) return true;
		}
		return false;
	}
	
	public function shift():ServerActionCommand {
		if (!hasCommandToExecute) throw new IllegalOperationError("no theard to extract");
		var temp:ServerActionCommand = _commands.shift();
		if (!temp.isLastCommand && _commands.length) _commands[0].becameFirst();
		return temp;
	}
	
	
}